//第一题
//将下面异步代码使用promise改造
//原题：
// setTimeout(() => {
//     var a = 'hello'
//     setTimeout(() => {
//         var b = 'lagou'
//         setTimeout(() => {
//             var c = 'I love U'
//             console.log(a+b+c)
//         }, 10);
//     }, 10);
// }, 10);

//改造后
new Promise((reslove,reject)=>{
    let a = 'hello'
    setTimeout(() => {
        reslove(a)
    }, 10);
}).then((value)=>{
    let b='lagou'
    setTimeout(() => {
        
    }, 10);
    return value+" "+b
}).then((value)=>{
    let c = 'I love U'
    setTimeout(() => {
        console.log(value+" "+c)
    }, 10);
})


//第二题
//基于以下代码完成四个练习
const _=require('lodash')
const fp=require('lodash/fp')

const cars = [{name:'Ferrari FF',horsepower:660,dollar_value:700000,in_stock:true},
{name:'Spyker C12 Zgato',horsepower:650,dollar_value:648000,in_stock:false},
{name:'Jaguar XKR-S',horsepower:550,dollar_value:132000,in_stock:false},
{name:'Audi R8',horsepower:525,dollar_value:114200,in_stock:false},
{name:'Aston Martin One-77',horsepower:750,dollar_value:1850000,in_stock:true},
{name:'Pagani Huayra',horsepower:700,dollar_value:1300000,in_stock:false},
]

//练习1  获取最后一条数据的in_stock属性

const getStock = fp.flowRight(fp.prop('in_stock'),fp.last)

console.log(getStock(cars))

//练习2 获取第一个car的name

const getName = fp.flowRight(fp.prop('name'),fp.first)

console.log(getName(cars))

//练习3 使用_average重构averageDollarValue
let _average = function(xs){
    return fp.reduce(fp.add,0,xs)/xs.length
}
const getAverage = fp.flowRight(_average,fp.map(fp.prop('dollar_value')))
console.log(getAverage(cars))

//练习4 sanitizeNames 返回一个下划线连续的小谢字符串，把name转换为['hello_world']的形式

const sanitizeNames = fp.map(fp.flowRight(fp.replace(/\W+/g,'_'),fp.lowerCase,fp.prop('name')))
console.log(sanitizeNames(cars))



//第三天
//基于以下代码完成四个练习,代码在support.js中


//练习1 使用fp.add(x,y)和fp.map(f,x)创建一个能让functor值增加的函数
const {Maybe,Container} = require('./support')
let maybe = Maybe.of([5,6,1])
let ex1 = ()=>{
   return maybe.map(x=>fp.map(fp.add(1),x))
}
console.log(ex1()._value)

//练习2 使用fp.first获取第一个元素

let xs = Container.of(['do','ray','me','fa','so','la','ti','do'])
let ex2 = ()=>{
    return xs.map(x=>fp.first(x))
}
console.log(ex2()._value)

//练习3 使用safeProp和fp.first找到user的首字母
let safeProp = fp.curry(function(x,o){
    return Maybe.of(o[x])
})
let user = {id:2,name:'Albert'}
let ex3 = ()=>{
    return safeProp('name',user).map(x=>fp.first(x))
}
console.log(ex3()._value)

//练习4 重写ex4，不要有if
//原版
// let ex4 = function(n){
//     if(n){
//         return parseInt(n)
//     }
// }

let ex4 = function(n){
    return Maybe.of(n).map(x=>parseInt(x))
}

//第四题  手写实现Promise源码

//初始化状态
const PENDING = "pending"; 
const FULFILLED = "fulfilled"; 
const REJECTED = "rejected"; 

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (e) {
      this.reject(e);
    }
  }

  status = PENDING;
  // 成功的返回值
  value = undefined;
  // 失败的返回值
  reason = undefined;
  // 成功回调数组
  successCallback = [];
  // 失败回调数组
  failCallback = [];

  resolve = (value) => {
    // 只允许单向改变你状态
    if (this.status !== PENDING) return;

    this.status = FULFILLED;

    this.value = value;

    // 如果有成功的回调则调用，数组的形式是为了多次调用then方法
    while (this.successCallback.length) this.successCallback.shift()();
  };
  reject = (reason) => {
   
    if (this.status !== PENDING) return;
    this.status = REJECTED;
    this.reason = reason;
    while (this.failCallback.length) this.failCallback.shift()();
  };
  then(successCallback, failCallback) {
    // 参数可选
    successCallback = successCallback ? successCallback : (value) => value;
    failCallback = failCallback
      ? failCallback
      : (reason) => {
          throw reason;
        };
    let promsie2 = new MyPromise((resolve, reject) => {
      // then方法返回一个promise，因此新建立一个promise
      if (this.status === FULFILLED) {
        //因为无法直接获取到promise2，因此用settimeout包裹
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve
            // 如果是promise对象 查看promsie对象返回的结果
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promsie2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            resolvePromise(promsie2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      } else {
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promsie2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promsie2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return promsie2;
  }

  finally(callback){
      //finally需要保持链式调用
      return this.then((value)=>{
          //需要等待promise执行完成
          return MyPromise.resolve(callback()).then(()=>value)
      },(error)=>{
          callback();
          return MyPromise.resolve(callback()).then(() => {throw error});
      })
  }

  catch(failCallback){
    return this.then(undefined,failCallback)
  }

  static all(array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      //需要等待所有promise都执行完毕
      function addData(key, value) {
        result[key] = value;
        index++;
        if (index === array.length) resolve(result);
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          //promise对象
          current.then(
            (value) => addData(i, value),
            (error) => {
              reject(error);
            }
          );
        } else {
          //普通值
          addData(i, array[i]);
        }
      }
    });
  }

  static resolve(value) {
      //如果是promise直接返回
    if (value instanceof MyPromise) {
      return value;
    } else {
        //否则包裹一个fullfilled的promise
      return new MyPromise((resolve) => resolve(value));
    }
  }
}

function resolvePromise(promsie2, x, resolve, reject) {
  if (promsie2 === x) {
    return reject(
      new TypeError("Chaining cycle detected for promise #<Promise>")
    );
  }
  if (x instanceof MyPromise) {
    // promise 对象
    // x.then(value => resolve(value), reason => reject(reason));
    x.then(resolve, reject);
  } else {
    // 普通值
    resolve(x);
  }
}

module.exports = MyPromise;


